home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / security / shadow-3.1.4 / age.c next >
Encoding:
C/C++ Source or Header  |  1992-04-05  |  6.3 KB  |  293 lines

  1. /*
  2.  * Copyright 1989, 1990, 1991, 1992, John F. Haugh II
  3.  * All rights reserved.
  4.  *
  5.  * Permission is granted to copy and create derivative works for any
  6.  * non-commercial purpose, provided this copyright notice is preserved
  7.  * in all copies of source code, or included in human readable form
  8.  * and conspicuously displayed on all copies of object code or
  9.  * distribution media.
  10.  */
  11.  
  12. #include <sys/types.h>
  13. #include <stdio.h>
  14. #include <errno.h>
  15. #include "config.h"
  16. #include "pwd.h"
  17. #include "shadow.h"
  18.  
  19. #ifndef    lint
  20. static    char    sccsid[] = "@(#)age.c    3.6    11:09:33    2/8/92";
  21. #endif
  22.  
  23. #define    DAY    (24L*3600L)
  24. #ifdef    ITI_AGING
  25. #define    SCALE    (DAY)
  26. #else
  27. #define    SCALE    (1)
  28. #endif
  29.  
  30. extern    time_t    time ();
  31. extern    char    *strdup();
  32.  
  33. /*
  34.  * pwd_to_spwd - create entries for new spwd structure
  35.  *
  36.  *    pwd_to_spwd() creates a new (struct spwd) containing the
  37.  *    information in the pointed-to (struct passwd).
  38.  */
  39.  
  40. static struct spwd *
  41. pwd_to_spwd (pw)
  42. struct    passwd    *pw;
  43. {
  44.     static    struct    spwd    tspwd;
  45.     struct    spwd    *sp = &tspwd;
  46.     time_t    t;
  47.  
  48.     /*
  49.      * Nice, easy parts first.  The name and passwd map directly
  50.      * from the old password structure to the new one.
  51.      */
  52.  
  53.     sp->sp_namp = strdup (pw->pw_name);
  54.     sp->sp_pwdp = strdup (pw->pw_passwd);
  55. #ifdef    ATT_AGE
  56.  
  57.     /*
  58.      * AT&T-style password aging maps the sp_min, sp_max, and
  59.      * sp_lstchg information from the pw_age field, which appears
  60.      * after the encrypted password.
  61.      */
  62.  
  63.     if (pw->pw_age[0]) {
  64.         t = (c64i (pw->pw_age[0]) * 7) * SCALE;
  65.         sp->sp_max = t;
  66.  
  67.         if (pw->pw_age[1]) {
  68.             t = (c64i (pw->pw_age[1]) * 7) * SCALE;
  69.             sp->sp_min = t;
  70.         } else
  71.             sp->sp_min = (10000L) * SCALE;
  72.  
  73.         if (pw->pw_age[1] && pw->pw_age[2]) {
  74.             t = (a64l (pw->pw_age + 2) * 7) * SCALE;
  75.             sp->sp_lstchg = t;
  76.         } else
  77.             sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  78.     } else {
  79.         sp->sp_min = 0;
  80.         sp->sp_max = (10000L * SCALE);
  81.         sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  82.     }
  83. #else    /* !ATT_AGE */
  84.     /*
  85.      * BSD does not use the pw_age field and has no aging information
  86.      * anywheres.  The default values are used to initialize the
  87.      * fields which are in the missing pw_age field;
  88.      */
  89.  
  90.     sp->sp_min = 0;
  91.     sp->sp_max = (10000L * SCALE);
  92.     sp->sp_lstchg = time ((time_t *) 0) / (DAY/SCALE);
  93. #endif    /* ATT_AGE */
  94.  
  95.     /*
  96.      * These fields have no corresponding information in the password
  97.      * file.  They are set to uninitialized values.
  98.      */
  99.  
  100.     sp->sp_warn = -1;
  101.     sp->sp_inact = -1;
  102.     sp->sp_expire = -1;
  103.     sp->sp_flag = -1;
  104.  
  105.     return sp;
  106. }
  107.  
  108. /*
  109.  * isexpired - determine if account is expired yet
  110.  *
  111.  *    isexpired calculates the expiration date based on the
  112.  *    password expiration criteria.
  113.  */
  114.  
  115. /*ARGSUSED*/
  116. int
  117. isexpired (pw, sp)
  118. struct    passwd    *pw;
  119. struct    spwd    *sp;
  120. {
  121.     long    clock;
  122.  
  123.     clock = time ((time_t *) 0) / (DAY/SCALE);
  124.  
  125.     /*
  126.      * Quick and easy - there is an expired account field
  127.      * along with an inactive account field.  Do the expired
  128.      * one first since it is worse.
  129.      */
  130.  
  131.     if (sp->sp_expire > 0 && sp->sp_expire < clock)
  132.         return 3;
  133.  
  134.     if (sp->sp_inact > 0 && sp->sp_lstchg > 0 && sp->sp_max > 0 &&
  135.             sp->sp_inact + sp->sp_lstchg + sp->sp_max < clock)
  136.         return 2;
  137.  
  138.     /*
  139.      * The last and max fields must be present for an account
  140.      * to have an expired password.  A maximum of >10000 days
  141.      * is considered to be infinite.
  142.      */
  143.  
  144.     if (sp->sp_lstchg == -1 ||
  145.             sp->sp_max == -1 || sp->sp_max >= (10000L*SCALE))
  146.         return 0;
  147.  
  148.     /*
  149.      * Calculate today's day and the day on which the password
  150.      * is going to expire.  If that date has already passed,
  151.      * the password has expired.
  152.      */
  153.  
  154.     if (sp->sp_lstchg + sp->sp_max < clock)
  155.         return 1;
  156.  
  157.     return 0;
  158. }
  159.  
  160. /*
  161.  * expire - force password change if password expired
  162.  *
  163.  *    expire() calls /bin/passwd to change the user's password
  164.  *    if it has expired.
  165.  */
  166.  
  167. int
  168. expire (pw, sp)
  169. struct    passwd    *pw;
  170. struct    spwd    *sp;
  171. {
  172.     int    status;
  173.     int    child;
  174.     int    pid;
  175.  
  176.     if (! sp)
  177.         sp = pwd_to_spwd (pw);
  178.  
  179.     /*
  180.      * See if the user's password has expired, and if so
  181.      * force them to change their password.
  182.      */
  183.  
  184.     switch (status = isexpired (pw, sp)) {
  185.         case 0:
  186.             return 0;
  187.         case 1:
  188.             printf ("Your password has expired.");
  189.             break;
  190.         case 2:
  191.             printf ("Your password is inactive.");
  192.             break;
  193.         case 3:
  194.             printf ("Your login has expired.");
  195.             break;
  196.     }
  197.  
  198.     /*
  199.      * Setting the maximum valid period to less than the minimum
  200.      * valid period means that the minimum period will never
  201.      * occur while the password is valid, so the user can never
  202.      * change that password.
  203.      */
  204.  
  205.     if (status > 1 || sp->sp_max < sp->sp_min) {
  206.         puts ("  Contact the system administrator.\n");
  207.         exit (1);
  208.     }
  209.     puts ("  Choose a new one.\n");
  210.     fflush (stdout);
  211.  
  212.     /*
  213.      * Close all the files so that unauthorized access won't
  214.      * occur.  This needs to be done anyway because those files
  215.      * might become stale after "passwd" is executed.
  216.      */
  217.  
  218.     endspent ();
  219.     endpwent ();
  220.     endsgent ();
  221.     endgrent ();
  222.  
  223.     /*
  224.      * Execute the /bin/passwd command.  The exit status will be
  225.      * examined to see what the result is.  If there are any
  226.      * errors the routine will exit.  This forces the user to
  227.      * change their password before being able to use the account.
  228.      */
  229.  
  230.     if ((pid = fork ()) == 0) {
  231.  
  232.         /*
  233.          * Set the UID to be that of the user.  This causes
  234.          * passwd to work just like it would had they executed
  235.          * it from the command line while logged in.
  236.          */
  237.  
  238.         if (setuid (pw->pw_uid))
  239.             _exit (errno);
  240.  
  241.         execl ("/bin/passwd", "passwd", pw->pw_name, (char *) 0);
  242.         puts ("Can't execute /bin/passwd");
  243.         fflush (stdout);
  244.  
  245.         _exit (errno);
  246.     } else if (pid == -1) {
  247.         perror ("passwd");
  248.         exit (errno);
  249.     }
  250.     while ((child = wait (&status)) != pid && child != -1)
  251.         ;
  252.  
  253.     if (child == pid && status == 0)
  254.         return 1;
  255.  
  256.     exit (1);
  257.     /*NOTREACHED*/
  258. }
  259.  
  260. /*
  261.  * agecheck - see if warning is needed for password expiration
  262.  *
  263.  *    agecheck sees how many days until the user's password is going
  264.  *    to expire and warns the user of the pending password expiration.
  265.  */
  266.  
  267. void
  268. agecheck (pw, sp)
  269. struct    passwd    *pw;
  270. struct    spwd    *sp;
  271. {
  272.     long    clock = time ((long *) 0) / (DAY/SCALE);
  273.     long    remain;
  274.  
  275.     if (! sp)
  276.         sp = pwd_to_spwd (pw);
  277.  
  278.     /*
  279.      * The last, max, and warn fields must be supported or the
  280.      * warning period cannot be calculated.
  281.      */
  282.  
  283.     if (sp->sp_lstchg == -1 || sp->sp_max == -1 || sp->sp_warn == -1)
  284.         return;
  285.  
  286.     if ((remain = (sp->sp_lstchg + sp->sp_max) - clock) <= sp->sp_warn) {
  287.         remain /= SCALE;
  288.         if (remain >= 0)
  289.             printf ("Your password will expire in %d %s.\n",
  290.                 remain, remain == 1 ? "day":"days");
  291.     }
  292. }
  293.